﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace myClient
{
    using MSNPSharp;
    using MSNPSharp.Core;
    using MSNPSharp.DataTransfer;

    public partial class frmMain : Form
    {
        // Create a Messenger object to use MSNPSharp.
        private Messenger messenger = new Messenger();

        private List<ConversationHandle> convhandles = new List<ConversationHandle>(0);

        private frmSelectRemote _frmSelectRemote;
        private frmAttibute _frmAttribute;
        private Contact _selectedContact = null;
        private ListViewItem lvDirLastSelected = null;

        private appIcons icons = new appIcons();

        //private SaveFileDialog saveFileDialog = new SaveFileDialog();

        public Messenger pMessenger
        {
            get
            {
                return messenger;
            }
        }

        public List<ConversationHandle> ConversationHandles
        {
            get
            {
                return convhandles;
            }
        }


        public frmMain()
        {
            InitializeComponent();

/*
            // ******* Listen traces *****
            TraceForm traceform = new TraceForm();
            traceform.Show();

#if DEBUG
            Settings.TraceSwitch.Level = System.Diagnostics.TraceLevel.Verbose;
#elif TRACE
            Settings.TraceSwitch.Level = System.Diagnostics.TraceLevel.Info;
#else
            Settings.TraceSwitch.Level = System.Diagnostics.TraceLevel.Warning;
#endif
*/            

            // set the events that we will handle
            // remember that the nameserver is the server that sends contact lists, notifies you of contact status changes, etc.
            // a switchboard server handles the individual conversation sessions.
            messenger.NameserverProcessor.ConnectionEstablished += new EventHandler<EventArgs>(NameserverProcessor_ConnectionEstablished);
            messenger.Nameserver.SignedIn += new EventHandler<EventArgs>(Nameserver_SignedIn);
            messenger.Nameserver.SignedOff += new EventHandler<SignedOffEventArgs>(Nameserver_SignedOff);
            messenger.NameserverProcessor.ConnectingException += new EventHandler<ExceptionEventArgs>(NameserverProcessor_ConnectingException);
            messenger.Nameserver.ExceptionOccurred += new EventHandler<ExceptionEventArgs>(Nameserver_ExceptionOccurred);
            messenger.Nameserver.AuthenticationError += new EventHandler<ExceptionEventArgs>(Nameserver_AuthenticationError);
            messenger.Nameserver.ServerErrorReceived += new EventHandler<MSNErrorEventArgs>(Nameserver_ServerErrorReceived);
            messenger.ConversationCreated += new EventHandler<ConversationCreatedEventArgs>(messenger_ConversationCreated);

            messenger.Nameserver.ContactOnline += new EventHandler<ContactEventArgs>(Nameserver_ContactOnline);
            messenger.Nameserver.ContactOffline += new EventHandler<ContactEventArgs>(Nameserver_ContactOffline);

            messenger.TransferInvitationReceived += new EventHandler<MSNSLPInvitationEventArgs>(messenger_TransferInvitationReceived);
            messenger.Nameserver.PingAnswer += new EventHandler<PingAnswerEventArgs>(Nameserver_PingAnswer);

            _frmSelectRemote = new frmSelectRemote(this);
            _frmSelectRemote.Hide();

            _frmAttribute = new frmAttibute();
            _frmAttribute.Hide();

            lvFile.SmallImageList = icons.IconList;
            lvFile.LargeImageList = icons.LargeIconList;
            lvFile.SmallImageList = icons.SmallIconList;

            this.Icon = icons.MainIcon;

        }


        //---------------------------
        private void NameserverProcessor_ConnectionEstablished(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(NameserverProcessor_ConnectionEstablished), sender, e);
                return;
            }

            messenger.Nameserver.AutoSynchronize = true;


            SetStatus("Connected to server");
        }

        private void Nameserver_SignedIn(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(Nameserver_SignedIn), sender, e);
                return;
            }

            SetStatus("Signed into the messenger network as " + messenger.Owner.Name);

            tmrKeepOnLine.Enabled = true;

            // set our presence status
            miLogin.Tag = 2;
            miLogin.Text = "Sign off";

            remoteToolStripMenuItem.Enabled = true;

            messenger.Owner.Status = PresenceStatus.Busy;

            Invoke(new EventHandler<EventArgs>(UpdateContactlist), sender, e);

        }

        private void Nameserver_SignedOff(object sender, SignedOffEventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler<SignedOffEventArgs>(Nameserver_SignedOff), sender, e);
                return;
            }

            SetStatus("Signed off from the messenger network");

            tmrKeepOnLine.Enabled = false;

            miLogin.Tag = 0;
            miLogin.Text = "&Sign In";

            cbDrv.Items.Clear();
            lvDir.Items.Clear();
            lvFile.Items.Clear();

            this.convhandles.Clear();
            this._selectedContact = null;
            this.lvDirLastSelected = null;

            remoteToolStripMenuItem.Enabled = false;
            SetViewEnable(false);
            SetRemoteEnable(false);

        }

        private void Nameserver_ExceptionOccurred(object sender, ExceptionEventArgs e)
        {
            // ignore the unauthorized exception, since we're handling that error in another method.
            if (e.Exception is UnauthorizedException)
                return;

            MessageBox.Show(e.Exception.ToString(), "Nameserver exception");
        }

        private void NameserverProcessor_ConnectingException(object sender, ExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.ToString(), "Connecting exception");
            SetStatus("Connecting failed");
        }

        private void Nameserver_AuthenticationError(object sender, ExceptionEventArgs e)
        {
            MessageBox.Show("Authentication failed, check your account or password.", e.Exception.InnerException.Message);
            SetStatus("Authentication failed");
        }

        private void Nameserver_ServerErrorReceived(object sender, MSNErrorEventArgs e)
        {
            // when the MSN server sends an error code we want to be notified.
            MessageBox.Show(e.MSNError.ToString(), "Server error received");
            SetStatus("Server error received");
        }


        private delegate ConversationHandle CreateConversationDelegate(Conversation conversation, Contact remote);

        private ConversationHandle CreateConversationHandle(Conversation conversation, Contact remote)
        {
            foreach (ConversationHandle chandle in ConversationHandles)
            {
                if (chandle.CanAttach(remote.Mail) != -1)
                {
                    chandle.AttachConversation(conversation);
                    return chandle;
                }
            }

            // create a new conversation. However do not show the window untill a message is received.
            // for example, a conversation will be created when the remote client sends wants to send
            // you a file. You don't want to show the conversation form in that case.
            ConversationHandle conversationHandle = new ConversationHandle(conversation, this, remote.Mail);
            // do this to create the window handle. Otherwise we are not able to call Invoke() on the
            // conversation form later.
            ConversationHandles.Add(conversationHandle);
            return conversationHandle;
        }


        private void messenger_ConversationCreated(object sender, ConversationCreatedEventArgs e)
        {
            // check if the request is initiated remote or by this object
            // if it is initiated remote then we have to create a conversation form. Otherwise the 
            // form is already created and we don't need to create another one.
            if (e.Initiator == null)
            {
                // use the invoke method to create the form in the main thread, ONLY create the form after a contact joined our conversation.
                e.Conversation.Switchboard.ContactJoined += delegate(object switchboard, ContactEventArgs args)
                {
                    this.Invoke(new CreateConversationDelegate(CreateConversationHandle), new object[] { e.Conversation, args.Contact });
                };
            }
        }

        void Nameserver_ContactOnline(object sender, ContactEventArgs e)
        {
            Invoke(new EventHandler<ContactEventArgs>(ContactOnlineOfline), sender, e);
        }
        void Nameserver_ContactOffline(object sender, ContactEventArgs e)
        {
            Invoke(new EventHandler<ContactEventArgs>(ContactOnlineOfline), sender, e);
        }

        void ContactOnlineOfline(object sender, ContactEventArgs e)
        {
            _frmSelectRemote.SortByStatus();
        }

        private void UpdateContactlist(object sender, EventArgs e)
        {
            if (messenger.Connected == false)
                return;

            _frmSelectRemote.SortByStatus();
        }

        private delegate DialogResult ShowFileDialogDelegate(FileDialog dialog);

        private DialogResult ShowFileDialog(FileDialog dialog)
        {
            return dialog.ShowDialog();
        }


        private void TransferSession_TransferFinished(object sender, EventArgs e)
        {
            P2PTransferSession session = (P2PTransferSession)sender;
            if (session != null && session.DataStream != null)
                MessageBox.Show("File:" + Environment.NewLine +
                    ((FileStream)session.DataStream).Name + Environment.NewLine +
                    " Transfer Finished!",
                    "Information", 
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
        }

        private void TransferSession_TransferAborted(object sender, EventArgs e)
        {
            P2PTransferSession session = (P2PTransferSession)sender;
            if (session != null && session.DataStream != null)
                MessageBox.Show("File:" + Environment.NewLine +
                    ((FileStream)session.DataStream).Name + Environment.NewLine +
                    " Transfer Aborted!",
                    "Information",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information);
        }

        private void messenger_TransferInvitationReceived(object sender, MSNSLPInvitationEventArgs e)
        {
            if (MessageBox.Show(
                "Do you want to download the file: \r\nFilename: " +
                e.Filename + "\r\nLength (bytes): " + e.FileSize,
                "Download file",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                //SaveFileDialog saveFileDialog = new SaveFileDialog();
                // by setting the Accept property in the EventArgs to true we give the transfer a green light				
                saveFileDialog.FileName = e.Filename;
                if ((DialogResult)Invoke(new ShowFileDialogDelegate(ShowFileDialog), new object[] { saveFileDialog }) == DialogResult.OK)
                {
                    e.TransferSession.DataStream = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.Write);
                    //e.Handler.AcceptTransfer (e);
                    e.Accept = true;
                    e.TransferSession.AutoCloseStream = true;
                    e.TransferSession.TransferFinished += new EventHandler<EventArgs>(TransferSession_TransferFinished);
                    e.TransferSession.TransferAborted += new EventHandler<EventArgs>(TransferSession_TransferAborted);
                }
            }
        }

        private int nextPing = 50;
        private void tmrKeepOnLine_Tick(object sender, EventArgs e)
        {
            if (nextPing > 0)
                nextPing--;
            if (nextPing == 0)
                messenger.Nameserver.SendPing();
        }

        void Nameserver_PingAnswer(object sender, PingAnswerEventArgs e)
        {
            nextPing = e.SecondsToWait;
        }


        //--------------------------

        private delegate void SetStatusDelegate(string status);
        private void SetStatus(string status)
        {
            if (InvokeRequired)
            {
                this.Invoke(new SetStatusDelegate(SetStatus), new object[] { status });
            }
            else
            {
                toolStripStatusLabel.Text = status;
            }
        }

        private void SetViewEnable(bool enable)
        {
            cbDrv.Enabled = enable;
            lvDir.Enabled = enable;
            lvFile.Enabled = enable;
        }

        private void SetRemoteEnable(bool enable)
        {
            getListToolStripMenuItem.Enabled = enable;
            runToolStripMenuItem.Enabled = enable;
        }

        public void RemoveConvsationHandle(ConversationHandle convh)
        {
            // invoke required
            //cbDrv.Items.Clear();
            //lvDir.Items.Clear();
            //lvFile.Items.Clear();

            //SetViewEnable(false);

            convhandles.Remove(convh);
        }

        // ::TEST::HANDSHAKE  ACK from remote
        public void AckHandshake()  
        {
            GetDrive();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void miLogin_Click(object sender, EventArgs e)
        {
            switch (Convert.ToInt32(miLogin.Tag))
            {
                case 0: // not connected -> connect
                    {
                        if (messenger.Connected)
                        {
                            SetStatus("Disconnecting from server");
                            messenger.Disconnect();
                        }

                        frmLogin frm = new frmLogin();
                        if (frm.ShowDialog() == DialogResult.OK)
                        {
                            // set the credentials, this is ofcourse something every MSNPSharp program will need to implement.
                            messenger.Credentials = new Credentials(frm.User, frm.Pass, MsnProtocol.MSNP15);


                            // inform the user what is happening and try to connecto to the messenger network.			
                            SetStatus("Connecting to server");
                            messenger.Connect();

                            miLogin.Tag = 1;
                            miLogin.Text = "&Cancel";
                        }

                        // note that Messenger.Connect() will run in a seperate thread and return immediately.
                        // it will fire events that informs you about the status of the connection attempt. 
                        // these events are registered in the constructor.
                    }
                    break;

                case 1: // connecting -> cancel
                    {
                        if (messenger.Connected)
                            messenger.Disconnect();

                        _frmSelectRemote.SortByStatus();

                        miLogin.Tag = 0;
                        miLogin.Text = "&Sign In";
                    }
                    break;

                case 2: // connected -> disconnect
                    {
                        if (messenger.Connected)
                            messenger.Disconnect();

                        _frmSelectRemote.SortByStatus();

                        miLogin.Tag = 0;
                        miLogin.Text = "&Sign In";
                    }
                    break;
            }
        }

        

        private delegate void RefreshListDelegate(string[] lists); 

        public void RefreshDrive(string[] drvlist)
        {
            if (InvokeRequired)
            {
                this.Invoke(new RefreshListDelegate(RefreshDrive), new object[] { drvlist });
                return;
            }

            cbDrv.Enabled = true;
            cbDrv.Items.Clear();
            cbDrv.SuspendLayout();

            if (drvlist != null)
            {
                for (int i = 1; i < drvlist.Length; i++)
                {
                    string name = drvlist[i];

                    if (name != null)
                    {
                        cbDrv.Items.Add(name);
                    }
                }
            }

            cbDrv.ResumeLayout();
        }
 
        public void RefreshDir(string[] dirlist)
        {
            if (InvokeRequired)
            {
                this.Invoke(new RefreshListDelegate(RefreshDir), new object[] { dirlist });
                return;
            }

            lvDir.Enabled = true;
            lvDir.Items.Clear();
            lvDir.SuspendLayout();

            if (dirlist != null)
            {
                string para1 = CmdParser.GetPara1(dirlist[0]);
                lvDir.Tag = para1; // set current dir of Listview

                for (int i = 1; i < dirlist.Length; i++)
                {
                    string name = dirlist[i];

                    if (name != null)
                    {
                        ListViewItem li = new ListViewItem(System.IO.Path.GetFileName(name));
                        li.ImageIndex = 0;
                        li.Tag = name;
                        lvDir.Items.Add(li);
                    }
                }

                if (!para1.Equals(""))
                {
                    string drive = System.IO.Path.GetPathRoot(para1);
                    string path = para1;// System.IO.Path.GetDirectoryName(para1);

                    if (!drive.Equals(path))
                    {
                        ListViewItem li = new ListViewItem("..");
                        li.ImageIndex = 0;
                        li.Tag = path.Substring(0, path.LastIndexOf('\\'));
                        lvDir.Items.Insert(0, li);
                    }

                    //lblPath.Text = para1;
                    SetStatus("Path: " + para1);
                }
            }

            lvDir.ResumeLayout();
        }

        public void RefreshFile(string[] filelist)
        {
            if (InvokeRequired)
            {
                this.Invoke(new RefreshListDelegate(RefreshFile), new object[] { filelist });
                return;
            }

            lvFile.Enabled = true;
            lvFile.Items.Clear();
            lvFile.SuspendLayout();

            if (filelist != null)
            {
                string para1 = CmdParser.GetPara1(filelist[0]);
                lvFile.Tag = para1; // set current dir of Listview

                for (int i = 1; i < filelist.Length; i++)
                {
                    string name = filelist[i];
                    if (name != null)
                    {
                        ListViewItem li = new ListViewItem(System.IO.Path.GetFileName(name));
                        //li.ImageIndex = 2;
                        li.ImageIndex = icons.GetIconIndex(System.IO.Path.GetExtension(name));
                        li.Tag = name;
                        lvFile.Items.Add(li);
                    }
                }
            }

            lvFile.ResumeLayout();
        }

        public void ShowFileInfo(string[] info)
        {
            if (_frmAttribute.Visible)
            {
                _frmAttribute.ShowFileInfo(info);
            }
        }

        private void GetDrive()
        {
            //cbDrv.Items.Clear(); // invoke
            cbDrv.Enabled = false;
            this.SendText("::shell::listdrv");
        }

        private void GetDir(string path)
        {
            lvDir.Items.Clear();
            lvDir.Enabled = false;
            this.SendText("::shell::listdir::" + path);
        }

        private void GetFile(string path)
        {
            lvFile.Items.Clear();
            lvFile.Enabled = false;
            this.SendText("::shell::listfile::" + path);
        }

        private void DownloadFile(string path)
        {
            this.SendText("::shell::download::" + path);
        }

        private void SendHandshake()
        {
            this.SendText("::test::handshake");
        }

        private void GetFileInfo(string path)
        {
            this.SendText("::shell::infofile::" + path);
        }

        private void selectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool viewstate = lvDir.Enabled;
            bool remotestate = getListToolStripMenuItem.Enabled;

            SetViewEnable(false);
            //SetRemoteEnable(false);

            if (_frmSelectRemote.ShowDialog() == DialogResult.OK)
            {
                Contact contact = _frmSelectRemote.SelectedContact;
                if (contact != null && !contact.Equals(this._selectedContact))
                {
                    this._selectedContact = contact;

                    cbDrv.Items.Clear();
                    lvDir.Items.Clear();
                    lvFile.Items.Clear();

                    this.SendHandshake();

                    SetRemoteEnable(true);

                    return;
                }
                //else
                //{
                //    SetViewEnable(viewstate);
                //    SetRemoteEnable(remotestate);
                //}
            }

            SetViewEnable(viewstate);
            //SetRemoteEnable(remotestate);
        }

        public void SendText(string text)
        {
            if (this._selectedContact != null)
            {
                foreach (ConversationHandle conv in ConversationHandles)
                {
                    int res = conv.CanAttach(_selectedContact.Mail);
                    if (res != -1)
                    {
                        conv.SendText(text);
                        return;
                    }
                }

                ConversationHandle handle = CreateConversationHandle(null, _selectedContact);
                handle.SendText(text);
            }
        }

        private void getListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            cbDrv.Items.Clear();
            GetDrive();
        }

        private void lvDir_Click(object sender, EventArgs e)
        {
           
        }

        private void lvDir_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvDir.SelectedItems.Count > 0)
            {
                lvDir.SelectedItems[0].ImageIndex = 1;
                if (lvDirLastSelected != null)
                    lvDirLastSelected.ImageIndex = 0;
                lvDirLastSelected = lvDir.SelectedItems[0];
            }
        }

        private void lvDir_DoubleClick(object sender, EventArgs e)
        {
            if (lvDir.SelectedItems.Count > 0)
            {
                ListViewItem li = lvDir.SelectedItems[0];
                string path = (string)li.Tag;

                string drive = System.IO.Path.GetPathRoot(path);
                string dir = path.Substring(drive.Length);

                if (drive.Equals(""))
                    drive = "C:";
                
                if (dir.Equals(""))
                    dir = "\\";

                path = drive + dir;

                GetDir(path);
                GetFile(path);
            }
        }

        private void downloadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lvFile.SelectedItems.Count > 0)
            {
                ListViewItem li = lvFile.SelectedItems[0];
                string filepath = (string)li.Tag;

                DownloadFile(filepath);
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmAbout frm = new frmAbout();
            frm.ShowDialog();
        }

        private void cbDrv_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbDrv.SelectedItem != null)
            {
                string drv = cbDrv.SelectedItem.ToString();
                GetDir(drv);
                GetFile(drv);
            }
        }

        private void runToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmCommand frm = new frmCommand(this);
            frm.ShowDialog();
        }

        private void viewStyleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                foreach (ToolStripMenuItem i in viewToolStripMenuItem.DropDownItems)
                    i.Checked = false;

                ToolStripMenuItem item = (sender as ToolStripMenuItem);
                View view = View.Details;

                if (item == largeIconToolStripMenuItem)
                    view = View.LargeIcon;
                else if (item == smallIconToolStripMenuItem)
                    view = View.SmallIcon;
                else if (item == listToolStripMenuItem)
                    view = View.List;
                else if (item == titleToolStripMenuItem)
                    view = View.Tile;
                else
                    view = View.Details;

                lvFile.View = view;
                item.Checked = true;

            }
            catch (Exception)
            { 
            }
        }

        private void attributesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (lvFile.SelectedItems.Count > 0)
            {
                ListViewItem li = lvFile.SelectedItems[0];
                string filepath = (string)li.Tag;
                GetFileInfo(filepath);

                _frmAttribute.ShowDialog();
            }
        }


    }
}
